home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
Sherlock 2.0
/
DevLibSrc
/
Main_DevLib
/
LIBcvt.c
< prev
next >
Wrap
Text File
|
1996-02-05
|
13KB
|
560 lines
/*
devlib: Integer and string conversion library.
Do not use Sherlock macros in this file.
Older versions of Sherlock routines called routines in this file.
All routines in this file convert an entity to a string in a buffer passed by the caller.
We could replace the calls to PERM_ASSERT by a routine that would fill the
buffer with a special pattern, say asterisks, when the buffer is too small.
I have not done so because I regard passing a too-small buffer as a programming error.
This point of view is debatable.
source: LIBcvt.c
started: November 4, 1993.
version:
February 5, 1996.
Added support for SYMANTEC_C
November 8, 1995.
Added cvt_frac for use by epadfrac.
Added cvt_l2s.
Moved cvt_date and cvt_time to LIBtime.c.
Call end_abort instead of abort.
Use PERM_ASSERT rather than cvt_check.
September 25, 1995.
Added support for Code Warrior.
*/
#include <LIBlib.h>
#include <LIBend.h>
#include <stdio.h> /* For sprintf. */
#include <string.h> /* For strlen. */
#include <time.h>
/*
#define CVT_USE_SPRINTF to use sprintf for formatting in various routines.
We might not want to use sprintf so as to avoid pulling in the floating point library.
An objection to _not_ using sprintf is that the cvt_l2s assumes a 2's complement
representation of signed numbers. You could consider this a bug.
There are subtle differences between the cvt_l2s, cvt_ul2s and cvt_hex2s routines
having to do with conversions between signed and unsigned quantities.
It seems clearest and safest to use three separate routines so that types
of all arguments are manifest. This may be an overly cautious approach.
*/
#undef CVT_USE_SPRINTF
char *
cvt_bool(bool b)
{
return (b) ? "TRUE" : "FALSE";
}
char *
cvt_cat2(char * buffer, int buf_size, char * s1, char * s2)
{
register size_t length1 = strlen(s1);
register size_t length2 = strlen(s2);
PERM_ASSERT(length1 + length2 + 1 < buf_size);
strcpy(buffer, s1);
strcpy(buffer+length1, s2);
return buffer;
}
char *
cvt_cat3(char * buffer, int buf_size, char * s1, char * s2, char *s3)
{
size_t length1 = strlen(s1);
size_t length2 = strlen(s2);
size_t length3 = strlen(s3);
PERM_ASSERT(length1 + length2 + length3 + 1 < buf_size);
strcpy(buffer, s1);
strcpy(buffer+length1, s2);
strcpy(buffer+length1+length2, s3);
return buffer;
}
char *
cvt_char(char * buffer, int buf_size, int c)
{
PERM_ASSERT(buf_size > 2);
buffer[0] = c;
buffer[1] = '\0';
return buffer;
}
/*
Return a descriptive message corresponding to a file error code.
*/
#if defined(THINK_C) || defined(SYMANTEC_C) || defined(applec) || defined(__MWERKS__)
#include <Errors.h>
#endif
char *
cvt_file_error(char * buffer, int buf_size, int OSErrCode)
{
#if defined(THINK_C) || defined(SYMANTEC_C) || defined(applec) || defined(__MWERKS__)
int n;
switch(OSErrCode) {
case -120: return "Directory not found";
case dirFulErr: return "Directory full";
case dskFulErr: return "Disk full";
case nsvErr: return "Volume not found";
case ioErr: return "I/O error";
case bdNamErr: return "Bad file name";
case fnOpnErr: return "File not open";
case eofErr: return "End of file";
case posErr: return "Position error";
case tmfoErr: return "Too many open files";
case fnfErr: return "File not found";
case wPrErr: return "Volume is software locked";
case fLckdErr: return "File is locked";
case fBsyErr: return "File is busy";
case dupFNErr: return "File exists";
case opWrErr: return "File is already open for writing";
case paramErr: return "Error in parameter list";
case rfNumErr: return "Access path not found";
case gfpErr: return "Error during GetFPos";
case volOffLinErr: return "Volume off line";
case permErr: return "File is locked";
case volOnLinErr: return "Volume on line";
case nsDrvErr: return "No such drive";
case noMacDskErr: return "Not a Macintosh disk";
case extFSErr: return "External file system";
case fsRnErr: return "Rename error";
case badMDBErr: return "Bad master director block";
case wrPermErr: return "Writing not allowed";
default:
strcpy(buffer, "Unknown error: ");
n = cvt_l2s(buffer + strlen(buffer), OSErrCode);
PERM_ASSERT(n < buf_size);
return buffer;
}
#else
PERM_ASSERT(buf_size >= 50);
strcpy(buffer, "file error code: ");
cvt_l2s(buffer + strlen(buffer), OSErrCode);
#endif
}
/*
Convert to a percentage of a2.
*/
char *
cvt_frac(char * buffer, int buf_size, long a1, long a2)
{
#ifdef CVT_USE_SPRINTF
int n = sprintf(buf, "%ld.%ld", a1/a2, ((10 * a1)/a2) % 10);
#else
int n = cvt_l2s(buffer, a1/a2);
strcat(buffer, ".");
n += 1 + cvt_l2s(buffer + strlen(buffer), ((10 * a1)/a2) % 10);
#endif
PERM_ASSERT(n < buf_size);
return buffer;
}
char *
cvt_hex(char * buffer, int buf_size, long hex)
{
#ifdef CVT_USE_SPRINTF
int n = sprintf(buffer, "%lx", hex);
#else
int n = cvt_hex2s(buffer, hex);
#endif
PERM_ASSERT(n < buf_size);
return buffer;
}
short
cvt_hex2s (char * buf, ulong val)
{
short length = 0;
/* Generate the hex digits in reverse order. */
{
short i;
for (i = 0; i < sizeof(long) * 2; i++) {
short digit = (val % 16);
buf[length++] = digit + ((digit < 10) ? '0' : ('a' - 10));
val /= 16;
}
}
/* Reverse the digits. */
{
short i = 0;
short j = length-1;
while (i < j) {
char temp = buf[j];
buf[j] = buf[i];
buf[i] = temp;
i++; j--;
}
}
buf[length] = '\0';
return length;
}
char *
cvt_int (char * buffer, int buf_size, int i)
{
#ifdef CVT_USE_SPRINTF
int n = sprintf(buffer, "%d", i);
#else
int n = cvt_l2s(buffer, i);
#endif
PERM_ASSERT(n < buf_size);
return buffer;
}
char *
cvt_long (char * buffer, int buf_size, long a)
{
#ifdef CVT_USE_SPRINTF
int n = sprintf(buffer, "%ld", a);
#else
int n = cvt_l2s(buffer, a);
#endif
PERM_ASSERT(n < buf_size);
return buffer;
}
short
cvt_l2s (char * buf, long val)
{
short length = 0;
/*
Check for the one case that can cause overflow.
In two's complement machines the largest negative number has no positive counterpart.
WARNING: this code assumes we have a 2's complement representation of signed numbers.
*/
if (val == 0x80000000) {
strcpy(buf, "-2147483648");
return strlen(buf);
}
if (val < 0) {
buf[length++] = '-';
val = -val; /* This can no longer overflow. */
PERM_ASSERT(val >= 0);
}
/* Generate the digits in reverse order. */
do {
buf[length++] = (val % 10) + '0';
val /= 10;
}
while (val > 0);
/* Reverse the digits. */
{
short i = (buf[0] == '-');
short j = length-1;
while (i < j) {
char temp = buf[j];
buf[j] = buf[i];
buf[i] = temp;
i++; j--;
}
}
buf[length] = '\0';
return length;
}
char *
cvt_paren(char * buffer, int buf_size, char *s)
{
PERM_ASSERT(2 + strlen(s) < buf_size);
strcpy(buffer, "(");
strcat(buffer, s);
strcat(buffer, ")");
return buffer;
}
/*
Convert to an "integer" percentage, like baseball batting averages.
*/
int
cvt_1000percent(long n, ulong tot)
{
double dn = n;
double dt = tot;
double d1000 = 1000;
double val = dn / dt;
if (n == 0 || tot == 0) {
return 0;
}
return (int) (d1000 * val);
}
/*
Convert to a percentage of n of total.
*/
char *
cvt_percent(char * buffer, int buf_size, long longv, ulong tot)
{
int n;
int percent;
percent = cvt_1000percent(longv, tot);
#ifdef CVT_USE_SPRINTF
n = sprintf(buffer, "%d.%d", (percent/10), (percent%10));
#else
n = cvt_l2s(buffer, percent/10);
strcat(buffer, ".");
n += 1 + cvt_l2s(buffer + strlen(buffer), percent % 10);
#endif
PERM_ASSERT(n < buf_size);
return buffer;
}
/*
Convert a pascal pointer to a C pointer.
*/
char *
cvt_pstring(char * buffer, int buf_size, pstring p)
{
register int i;
register int length = *p++;
PERM_ASSERT(length+1 < buf_size);
for (i = 0; i < length; i++) {
buffer[i] = *p++;
}
buffer[i] = '\0';
return buffer;
}
char *
cvt_ptr (char * buffer, int buf_size, void * p)
{
#ifdef CVT_USE_SPRINTF
int n = sprintf(buffer, "%p", p);
#else
int n = cvt_hex2s(buffer, (ulong) p);
#endif
PERM_ASSERT(n < buf_size);
return buffer;
}
/*
Return a string in quotes.
No quoting of quotes is done within the string.
*/
char *
cvt_quote(char * buffer, int buf_len, char * s)
{
PERM_ASSERT(strlen(s) + 3 < buf_len);
strcpy(buffer, "\"");
strcat(buffer, s);
strcat(buffer, "\"");
return buffer;
}
/*
Given a static string, return the short file name of the string.
*/
char *
cvt_short_fn(char * file_name)
{
#if defined(THINK_C) || defined(SYMANTEC_C) || defined(applec) || defined(TUPLE_C) || defined(__MWERKS__)
/* Scan backwards looking for a colon. */
register size_t n = strlen(file_name)-2;
/*
Bug fix: 11/8/93:
size_t may be unsigned, in which case i < 0 is *never* true.
*/
register long i;
for (i = n; i >= 0; i--) {
if (file_name[i] == ':') {
return file_name + i + 1;
}
}
return file_name;
#else
return file_name;
#endif
}
/*
Test this module for blunders.
*/
#define BUF_SIZE 50
#ifndef PRODUCTION
void
cvt_test(void)
{
char buf [BUF_SIZE];
ecnl();
es("cvt_test...\n\n");
es("error code 1234: "); es(cvt_file_error(buf, BUF_SIZE, 1234)); enl();
es("TRUE: "); es(cvt_bool(TRUE)); enl();
es("FALSE: "); es(cvt_bool(FALSE)); enl();
es("char A: "); es(cvt_char(buf, BUF_SIZE, 'A')); enl();
#if 0 // Don't force the floating library to be linked in
es("The following requires the floating library to be linked in...\n");
es("Do NOT use ANSI-small: sprintf(\"%f\"...) will return 0!\n");
es("double 1.1: "); es(cvt_double(buf, BUF_SIZE, (double) 1.1)); enl();
#endif
es("int -25: "); es(cvt_int (buf, BUF_SIZE, -25)); enl();
es("long 987654321: "); es(cvt_long (buf, BUF_SIZE, 987654321)); enl();
es("hex abcdef00: "); es(cvt_hex (buf, BUF_SIZE, 0xabcdef00)); enl();
es("hex 01236789: "); es(cvt_hex (buf, BUF_SIZE, 0x01236789)); enl();
es("ptr 1158a2f "); es(cvt_ptr (buf, BUF_SIZE, (void *) 0x1158a2f)); enl();
es("uint 32000 "); es(cvt_uint (buf, BUF_SIZE, (unsigned) 32000)); enl();
es("uint 0x8000 "); es(cvt_uint (buf, BUF_SIZE, (unsigned) 0x8000)); enl();
es("ulong 87654321 "); es(cvt_ulong (buf, BUF_SIZE, (unsigned long) 87654321)); enl();
es("ulong 0x80000000 "); es(cvt_ulong (buf, BUF_SIZE, (unsigned long) 0x80000000)); enl();
es("long 0x80000000 "); es(cvt_long (buf, BUF_SIZE, (long) 0x80000000)); enl();
es("ulong 2147483648 "); es(cvt_ulong (buf, BUF_SIZE, (ulong) 2147483648)); enl();
es("long 2147483648 "); es(cvt_long (buf, BUF_SIZE, (long) 2147483648)); enl();
es("quote A: "); es(cvt_quote (buf, BUF_SIZE, "A")); enl();
es("pstring \\pABCD ");es(cvt_pstring (buf, BUF_SIZE, "\pABCD")); enl();
es("trunc(ABC,2) "); es(cvt_trunc (buf, BUF_SIZE, "ABC", 2)); enl();
es("percent(45,200) "); es(cvt_percent (buf, BUF_SIZE, 45, 200)); enl();
ecnls(2);
es("test of exxx routines that may call cvt routines...\n\n");
es("int -25: "); epadint (-25, 0); enl();
es("long 987654321: "); epadlong (987654321, 0); enl();
es("hex abcdef00: "); epadhex (0xabcdef00, 0); enl();
es("hex 01236789: "); epadhex (0x01236789, 0); enl();
es("ptr 1158a2f "); epadptr ((void *) 0x1158a2f, 0); enl();
es("uint 32000 "); epaduint ((unsigned) 32000, 0); enl();
es("uint 0x8000 "); epaduint ((unsigned) 0x8000, 0); enl();
es("ulong 87654321 "); epadulong ((unsigned long) 87654321, 0); enl();
es("ulong 0x80000000 "); epadulong ((unsigned long) 0x80000000, 0); enl();
es("long 0x80000000 "); epadlong ((long) 0x80000000, 0); enl();
es("ulong 2147483648 "); epadulong ((ulong) 2147483648, 0); enl();
es("long 2147483648 "); epadlong ((long) 2147483648, 0); enl();
es("frac(45,200) "); epadfrac (45, 200, 0); enl();
}
#endif /* PRODUCTION */
/*
Return a string truncated to n digits.
*/
char *
cvt_trunc (char * buffer, int buf_size, char *s, int n)
{
register int i;
register size_t length = strlen(s);
PERM_ASSERT(n < buf_size);
for (i = 0; i < n; i++) {
buffer[i] = *s++;
}
buffer[i] = '\0';
return buffer;
}
char *
cvt_uint (char * buffer, int buf_size, uint ui)
{
#ifdef CVT_USE_SPRINTF
int n = sprintf(buffer, "%u", ui);
#else
int n = cvt_ul2s(buffer, ui);
#endif
PERM_ASSERT(n < buf_size);
return buffer;
}
char *
cvt_ulong (char * buffer, int buf_size, ulong ul)
{
#ifdef CVT_USE_SPRINTF
int n = sprintf(buffer, "%lu", ul);
#else
int n = cvt_ul2s(buffer, ul);
#endif
PERM_ASSERT(n < buf_size);
return buffer;
}
short
cvt_ul2s (char * buf, ulong val)
{
short length = 0;
/* Generate the digits in reverse order. */
do {
buf[length++] = (val % 10) + '0';
val /= 10;
}
while (val > 0);
/* Reverse the digits. */
{
short i = 0;
short j = length-1;
while (i < j) {
char temp = buf[j];
buf[j] = buf[i];
buf[i] = temp;
i++; j--;
}
}
buf[length] = '\0';
return length;
}